//@author A0096759E

package testcases;


import static org.junit.Assert.assertEquals;
import logic.CommandDecoder;

import org.junit.Test;

import storage.ScheduleEvent;
import storage.Storage;

public class IntegratedTesting {
	
	private static final String SUCCESS_ALL_EVENTS_CLEARED = "All events have been cleared from your Schedule!";
	private static final String SUCCESS_ADDED_EVENT = "The event \"%s\" has been added successfully to your Schedule!";
	private static final String SUCCESS_ADDED_EVENT_SAME_NAME = "A task with the same task name exists already.\nThe event \"%s\" has been added successfully to your Schedule!";
	private static final String SUCCESS_ADDED_EVENT_SAME_TIME = "There is a time collision with another task.\nThe event \"%s\" has been added successfully to your Schedule!";
	private static final String SUCCESS_ADDED_EVENT_ALR_EXIST = "The task is already added\nThe event \"%s\" has been added successfully to your Schedule!";
	private static final String SUCCESS_DELETED_EVENT = "The event \"%s\" has been removed successfully from your Schedule!";
	private static final String SUCCESS_MSG_MARKED_DONE = "Successfully marked %s [DONE]!";
	private static final String SUCCESS_MSG_MARKED_UNDONE = "Successfully marked %s [UNDONE]!";
	private static final String SUCCESS_MSG_TASK_MODIFIED = "Successfully Modified task.";
	private static final String SEARCH_MESSAGE = "Entries with search term \"%s\" in your Schedule:";
	private static final String SEARCH_MESSAGE_DATE_RANGE = "Entries from \"%s\" to \"%s\" in your Schedule:";
	private static final String SEARCH_RESULT_TEMPLATE = "%s\n\n%s";
	private static final String ERROR_MSG_CANNOT_REDO = "Unable to redo! No undone command found!";
	private static final String ERROR_MSG_INVALID_INDEX = "You have input an Invalid Index! Please Re-try!";
	private static final String ERROR_UNABLE_TO_MODIFY = "Task could not be modified";
	private static final String ERROR_MSG_ALREADY_DONE = "This Event is already Done!";
	private static final String ERROR_MSG_ALREADY_UNDONE = "This Event is already Undone!";
	private static final String ERROR_MSG_INVALID_COMMAND = "ERROR! Invalid command format! Please try again!";
	private static final String ERROR_PARAMETER_NO_INPUT = "You add in parameter but no new inputs.";

	
	@Test
	public void test() {
		Storage storage = new Storage("integratedTesting.txt");
		CommandDecoder commandDecoder = new CommandDecoder(storage);
		String phase1Adding, phase2Adding,  phase3Deleting, phase4Modifying, phase5Searching, phase6Searching, phase7Marking;
		assertEquals(SUCCESS_ALL_EVENTS_CLEARED,storage.clearAllEvents());
		StringBuilder correctSequence = new StringBuilder();
		
		//Create Events to add first
		ScheduleEvent eventToAdd1 = new ScheduleEvent(2, "Carrots Are Nice", "21121991", "1100", "1230");
		ScheduleEvent eventToAdd2 = new ScheduleEvent(1, "Banana Milkshake", "22121991", "1200");
		ScheduleEvent eventToAdd3 = new ScheduleEvent(0, "Banana Milkshake", "99999999");
		ScheduleEvent eventToAdd4 = new ScheduleEvent(2, "Donkeys Are Short", "21121991", "1000", "1130");
		ScheduleEvent eventToAdd5 = new ScheduleEvent(2, "Carrots Are Nice", "21121991", "1100", "1230");
		ScheduleEvent eventToAdd6 = new ScheduleEvent(2, "Donkeys Are Short", "23121991", "1000", "1130");

		//Create Adding Results
		correctSequence.append("1. " + eventToAdd4.toString()+"\n\n");
		correctSequence.append("2. " + eventToAdd1.toString()+"\n\n");
		correctSequence.append("3. " + eventToAdd2.toString()+"\n\n");
		correctSequence.append("4. " + eventToAdd3.toString());
		
		phase1Adding = correctSequence.toString();
		
		correctSequence = new StringBuilder();		
		correctSequence.append("1. " + eventToAdd4.toString()+"\n\n");
		correctSequence.append("2. " + eventToAdd1.toString()+"\n\n");
		correctSequence.append("3. " + eventToAdd5.toString()+"\n\n");
		correctSequence.append("4. " + eventToAdd2.toString()+"\n\n");
		correctSequence.append("5. " + eventToAdd3.toString());

		phase2Adding = correctSequence.toString();
		
		correctSequence = new StringBuilder();		
		correctSequence.append("1. " + eventToAdd1.toString()+"\n\n");
		correctSequence.append("2. " + eventToAdd2.toString()+"\n\n");
		correctSequence.append("3. " + eventToAdd3.toString());

		phase3Deleting = correctSequence.toString();
		
		correctSequence = new StringBuilder();		
		correctSequence.append("1. " + eventToAdd2.toString()+"\n\n");
		correctSequence.append("2. " + eventToAdd6.toString()+"\n\n");
		correctSequence.append("3. " + eventToAdd3.toString());

		phase4Modifying = correctSequence.toString();
		
		correctSequence = new StringBuilder();		
		correctSequence.append("2. " + eventToAdd6.toString());

		phase5Searching = correctSequence.toString();
		
		correctSequence = new StringBuilder();		
		correctSequence.append("1. " + eventToAdd2.toString());

		phase6Searching = correctSequence.toString();
		
		correctSequence = new StringBuilder();		
		eventToAdd2.setIsDone();
		correctSequence.append("1. " + eventToAdd2.toString()+"\n\n");
		correctSequence.append("2. " + eventToAdd6.toString()+"\n\n");
		correctSequence.append("3. " + eventToAdd3.toString());

		phase7Marking = correctSequence.toString();
		
		//Start Testing ADD first
		assertEquals(String.format(SUCCESS_ADDED_EVENT, "Carrots Are Nice" ),commandDecoder.decodeUserInput("add Carrots Are Nice on 21121991 from 1100 to 1230"));
		assertEquals(String.format(SUCCESS_ADDED_EVENT, "Banana Milkshake" ),commandDecoder.decodeUserInput("add Banana Milkshake on 22121991 by 1200"));
		assertEquals(String.format(SUCCESS_ADDED_EVENT_SAME_NAME, "Banana Milkshake" ),commandDecoder.decodeUserInput("add Banana Milkshake"));
		assertEquals(String.format(SUCCESS_ADDED_EVENT_SAME_TIME, "Donkeys Are Short" ),commandDecoder.decodeUserInput("add Donkeys Are Short on 21121991 from 1000 to 1130"));
		assertEquals(String.format(SUCCESS_ADDED_EVENT_ALR_EXIST, "Carrots Are Nice" ),commandDecoder.decodeUserInput("add Carrots Are Nice on 21121991 from 1100 to 1230"));
		
		assertEquals(phase2Adding, commandDecoder.decodeUserInput("display all"));
		
		//Now we check UNDO and REDO
		assertEquals(String.format(SUCCESS_DELETED_EVENT, "Carrots Are Nice"), commandDecoder.decodeUserInput("undo"));
		
		//Checking with previous case when the last item was not added.
		assertEquals(phase1Adding, commandDecoder.decodeUserInput("display all"));
		assertEquals(String.format(SUCCESS_ADDED_EVENT_ALR_EXIST, "Carrots Are Nice"), commandDecoder.decodeUserInput("redo"));
		
		//Check if REDO did work, resuming previous state
		assertEquals(phase2Adding, commandDecoder.decodeUserInput("display all"));
		
		//Go back to previous state to set up for next test
		assertEquals(String.format(SUCCESS_DELETED_EVENT, "Carrots Are Nice"), commandDecoder.decodeUserInput("undo"));
		
		//CHECK Delete
		assertEquals(String.format(SUCCESS_DELETED_EVENT, "Donkeys Are Short"), commandDecoder.decodeUserInput("delete 1"));
		assertEquals(phase3Deleting, commandDecoder.decodeUserInput("display all"));
		
		//CHECK if REDO Stack has been cleared
		assertEquals(ERROR_MSG_CANNOT_REDO, commandDecoder.decodeUserInput("redo"));
		
		//Test Fringe Cases for Delete
		assertEquals(ERROR_MSG_INVALID_INDEX, commandDecoder.decodeUserInput("delete null"));
		assertEquals(ERROR_MSG_INVALID_INDEX, commandDecoder.decodeUserInput("delete -1"));
		
		//TEST Modifying Whole event
		assertEquals(SUCCESS_MSG_TASK_MODIFIED, commandDecoder.decodeUserInput("modify 1 n Donkeys Are Short d 23121991 st 1000 et 1130"));
		assertEquals(phase4Modifying, commandDecoder.decodeUserInput("display all"));
		
		//Test Fringe Cases for Modify
		assertEquals(ERROR_PARAMETER_NO_INPUT, commandDecoder.decodeUserInput("modify 1 st"));
		assertEquals(ERROR_UNABLE_TO_MODIFY, commandDecoder.decodeUserInput("modify 3 st 0900"));
		assertEquals(ERROR_UNABLE_TO_MODIFY, commandDecoder.decodeUserInput("modify 3 et 1000"));
		
		//Test Search
		assertEquals(String.format(SEARCH_RESULT_TEMPLATE, String.format(SEARCH_MESSAGE, "donkey") ,phase5Searching), commandDecoder.decodeUserInput("search donkey"));
		assertEquals(String.format(SEARCH_RESULT_TEMPLATE, String.format(SEARCH_MESSAGE_DATE_RANGE, "01121991", "22121991") ,phase6Searching), commandDecoder.decodeUserInput("search 01121991 22121991"));
		
		//Test Marking Done
		assertEquals(String.format(SUCCESS_MSG_MARKED_DONE, "Banana Milkshake"), commandDecoder.decodeUserInput("mark 1 done"));
		assertEquals(ERROR_MSG_ALREADY_DONE, commandDecoder.decodeUserInput("mark 1 done"));
		assertEquals(phase7Marking, commandDecoder.decodeUserInput("display all"));
		
		//Test Marking NOT DONE to return to phase4Modifying state
		assertEquals(String.format(SUCCESS_MSG_MARKED_UNDONE, "Banana Milkshake"), commandDecoder.decodeUserInput("mark 1 undone"));
		assertEquals(ERROR_MSG_ALREADY_UNDONE, commandDecoder.decodeUserInput("mark 1 undone"));
		assertEquals(phase4Modifying, commandDecoder.decodeUserInput("display all"));
		
		//Test Fringe Cases for Marking
		assertEquals(ERROR_MSG_INVALID_COMMAND, commandDecoder.decodeUserInput("mark 1"));
		assertEquals(ERROR_MSG_INVALID_COMMAND, commandDecoder.decodeUserInput("mark -1 done"));
		assertEquals(ERROR_MSG_INVALID_COMMAND, commandDecoder.decodeUserInput("mark 99999 done"));
	}
}
